package com.multitrack.main;

import static com.multitrack.datatype.SocketMessage.CREATE_EVENT;
import static com.multitrack.datatype.SocketMessage.EVENT_JOIN;
import static com.multitrack.datatype.SocketMessage.EVENT_QUIT;
import static com.multitrack.datatype.SocketMessage.IS_IN_EVENT;
import static com.multitrack.datatype.SocketMessage.REQUEST_EVENT_INFO;
import static com.multitrack.datatype.SocketMessage.REQUEST_EVENT_LIST;
import static com.multitrack.datatype.SocketMessage.getEnum;

import java.util.Iterator;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.nfc.NfcAdapter;
import android.nfc.tech.NfcF;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.multitrack.datatype.Event;
import com.multitrack.datatype.EventData;
import com.multitrack.datatype.Identity;
import com.multitrack.datatype.IdentityList;
import com.multitrack.datatype.STATE;
import com.multitrack.datatype.SocketMessage;
import com.multitrack.datatype.TYPE;
import com.multitrack.map.EventMapActivity;
import com.multitrack.util.CloseAlertDialog;
import com.multitrack.util.CommunicationManager;
import com.multitrack.util.EventListAdapter;
import com.multitrack.util.EventSQLite;
import com.multitrack.util.Progress;
import com.multitrack.util.ThreadManager;
import com.multitrack.util.SQLite;

public class EventActivity extends Activity {
	static final String TAG = "EventActivity";

	static final int EVENT_NAME_MAX_LENGTH = 50;

	private ListView eventListView;
	private EventListAdapter adapter;
	private IdentityList events;
	private EventSQLite mHelper;
	private Event currEvent;
	private String eventName;
	private String eventPassword;
	private TextView createEventText;

	private Progress mProgress;
	private CommunicationManager requestEventList, requestCheckInEvent,
			requestCreateEvent, requestJoinEvent, requestEvent,
			requestQuitEvent;

	private NfcAdapter mAdapter;
	private PendingIntent mPendingIntent;
	private IntentFilter[] mFilters;
	private String[][] mTechLists;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.event_activity);

		mAdapter = NfcAdapter.getDefaultAdapter(this);
		if (mAdapter != null) {
			standByNfc();
		} else {
			// NFC 사용불가
		}

		createEventText = (TextView) findViewById(R.id.new_event_text);

		eventListView = (ListView) findViewById(R.id.event_list);
		events = new IdentityList();
		adapter = new EventListAdapter(this, R.layout.event_item_activity,
				events);
		eventListView.setAdapter(adapter);
		eventListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
		eventListView.setOnItemClickListener(eventItemClickListener);

		mHelper = new EventSQLite(this);

		mProgress = new Progress(this);
		mProgress.setMessage(R.string.loading);

		executeCheckInEvent(mHelper.dbGetMyId());

	}

	private void standByNfc() {
		Intent targetIntent = new Intent(this, EventTagActivity.class);
		targetIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
		mPendingIntent = PendingIntent.getActivity(this, 0, targetIntent, 0);

		IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
		try {
			ndef.addDataType("*/*");
		} catch (MalformedMimeTypeException e) {
			throw new RuntimeException("fail", e);
		}

		mFilters = new IntentFilter[] { ndef, };

		mTechLists = new String[][] { new String[] { NfcF.class.getName() } };
	}

	public void onResume() {
		super.onResume();
		if (mAdapter != null) {
			mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters,
					mTechLists);
		}
		executeGetEventList();
	}

	public void onPause() {
		super.onPause();

		if (mAdapter != null) {
			mAdapter.disableForegroundDispatch(this);
		}
	}

	public void mOnClick(View v) {
		final LinearLayout linear = (LinearLayout) View.inflate(this,
				R.layout.create_event_activity, null);

		switch (v.getId()) {

		case R.id.new_event_text:

			createEventText.setClickable(false);

			OnClickListener listener = new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {

					EditText createEventName = (EditText) linear
							.findViewById(R.id.create_event_name);
					EditText createEventPass = (EditText) linear
							.findViewById(R.id.event_password);

					/*
					 * 이벤트 이름, 패스워드 제한 함수 필요함.
					 */
					eventName = createEventName.getText().toString();

					CheckBox checkBoxPassword = (CheckBox) linear
							.findViewById(R.id.check_event_password);
					if (checkBoxPassword.isChecked()) {
						eventPassword = createEventPass.getText().toString();
					} else {
						eventPassword = null;
					}

					if (eventName.equals("")) {
						Toast.makeText(EventActivity.this,
								R.string.input_event_name, Toast.LENGTH_SHORT)
								.show();
						return;
					} else if (eventName.length() >= EVENT_NAME_MAX_LENGTH) {
						Toast.makeText(EventActivity.this,
								R.string.long_event_name, Toast.LENGTH_SHORT)
								.show();
						return;
					}

					currEvent = new Event();
					currEvent.setLeaderId(mHelper.dbGetMyId());
					currEvent.setId(mHelper.dbGetCurrTime());
					currEvent.setName(eventName);
					currEvent.setPw(eventPassword);

					executeCreateEvent(currEvent);
				}
			};

			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			AlertDialog dialog;

			builder.setTitle(R.string.create_event_title).setView(linear)
					.setPositiveButton(R.string.event_make_btn, listener)
					.setNegativeButton(R.string.cancel, null);

			dialog = builder.create();

			if (dialog != null && dialog.isShowing()) {
				dialog.dismiss();
				break;
			}

			dialog.show();

			createEventText.setClickable(true);
			break;
		}
	}

	// event 항목 선택 리스너
	AdapterView.OnItemClickListener eventItemClickListener = new AdapterView.OnItemClickListener() {
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			EventData eventIdData = new EventData();
			eventIdData.setEventId(events.get(position).getId());
			executeGetEvent(eventIdData);
		}

	};

	/**
	 * SubThread -> Messages -> Handler -> MainThread(UI)
	 */
	Handler mHandler = new Handler() {

		SocketMessage message;
		STATE resultState;
		Object resultValue;

		@Override
		public void handleMessage(Message msg) {
			message = getEnum(msg.arg1);
			resultState = STATE.getEnum(msg.what);
			resultValue = msg.obj;

			if (mProgress.isShowing()) {
				mProgress.dismiss();
			}

			switch (message) {

			case EVENT_QUIT:
				receiveQuitEvent();
				break;

			case REQUEST_EVENT_INFO:
				receiveEvent();
				break;

			case EVENT_JOIN:
				receiveJoinEvent();
				break;

			case CREATE_EVENT:
				receiveCreateEvent();
				break;

			case IS_IN_EVENT:
				receiveCheckInEvent();
				break;

			case REQUEST_EVENT_LIST:
				receiveEventList();
				break;

			default:
				unknownMessage(message);
				break;
			}
		}

		/*
		 * 
		 */
		private void receiveQuitEvent() {
			switch (resultState) {
			case SOCKET_SUCCESS:
				receiveQuitEventSuccess();
				break;

			case SOCKET_FAIL:
				uponFail();
				break;

			case SOCKET_EXCEPTION:
				OnClickListener listener = new OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						executeQuitEvent();
					}
				};
				UponException(listener, null);
				break;

			default:
				unknownMessage(resultState);
				break;
			}
		}

		private void receiveQuitEventSuccess() {
			switch ((SocketMessage) resultValue) {
			case SQL_QUERY_SUCCESS:
				SQLite mHelper = new SQLite(getApplicationContext());
				mHelper.dbDeleteEvent();
				mHelper.close();
				break;

			case SQL_QUERY_FAIL:
				new CloseAlertDialog(EventActivity.this, R.string.notice,
						R.string.fail_quit_event, null);
				break;

			default:
				unknownMessage((SocketMessage) resultValue);
				break;
			}

		}

		/*
		 * 
		 */
		private void receiveEvent() {
			switch (resultState) {
			case SOCKET_SUCCESS:
				currEvent = (Event) resultValue;
				receiveEventSuccess();
				break;

			case SOCKET_FAIL:
				uponFail();
				break;

			case SOCKET_EXCEPTION:
				OnClickListener listener = new OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						executeJoinEvent(currEvent);
					}
				};
				UponException(listener, null);
				break;

			default:
				unknownMessage(resultState);
				break;
			}
		}

		private void receiveEventSuccess() {
			if (currEvent != null) {
				executeJoinEvent(currEvent);
			} else {
				OnClickListener listener = new OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						executeGetEventList();
					}
				};
				new CloseAlertDialog(EventActivity.this, R.string.notice,
						R.string.cannot_find_event, listener).show();
			}
		}

		/*
		 * 
		 */
		private void receiveJoinEvent() {
			switch (resultState) {
			case SOCKET_SUCCESS:
				receiveJoinEventSuccess();
				break;

			case SOCKET_FAIL:
				uponFail();
				break;

			case SOCKET_EXCEPTION:
				OnClickListener listener = new OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						executeJoinEvent(currEvent);
					}
				};
				UponException(listener, null);
				break;

			default:
				unknownMessage(resultState);
				break;
			}
		}

		private void receiveJoinEventSuccess() {

			switch ((SocketMessage) resultValue) {

			case BLACK_LIST:
				new CloseAlertDialog(EventActivity.this, R.string.notice,
						R.string.deny_join_event, null).show();
				break;

			case ALREADY_JOIN_MEMBER_IN_EVENT:
			case SQL_QUERY_SUCCESS:
				startEventMap(currEvent);
				break;

			case SQL_QUERY_FAIL:
				break;

			case SQL_QUERY_ERROR:

				break;

			default:
				unknownMessage((SocketMessage) resultValue);
				break;
			}
		}

		/*
		 * 
		 */
		private void receiveCreateEvent() {
			switch (resultState) {
			case SOCKET_SUCCESS:
				receiveCreateEventSuccess();
				break;

			case SOCKET_FAIL:
				uponFail();
				break;

			case SOCKET_EXCEPTION:
				OnClickListener listener = new OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						executeCreateEvent(currEvent);
					}
				};

				UponException(listener, null);
				break;

			default:
				unknownMessage(resultState);
				break;
			}
		}

		private void receiveCreateEventSuccess() {

			switch ((SocketMessage) resultValue) {
			case SQL_QUERY_SUCCESS:
				startEventMap(currEvent);
				break;

			case SQL_QUERY_FAIL:
				break;

			case SQL_QUERY_ERROR:
				break;

			default:
				unknownMessage((SocketMessage) resultValue);
				break;
			}

		}

		/*
		 * 
		 */
		private void receiveCheckInEvent() {
			switch (resultState) {
			case SOCKET_SUCCESS:
				receiveCheckInEventSuccess();
				break;

			case SOCKET_FAIL:
				uponFail();
				break;

			case SOCKET_EXCEPTION:
				executeCheckInEvent(mHelper.dbGetMyId());
				break;

			default:
				unknownMessage(resultState);
				break;
			}
		}

		private void receiveCheckInEventSuccess() {

			switch ((SocketMessage) resultValue) {
			case ID_FOUND:

				OnClickListener positive = new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						EventData memberIdData = new EventData();
						memberIdData.setMemberId(mHelper.dbGetMyId());
						executeGetEvent(memberIdData);
					}
				};

				OnClickListener negative = new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						executeQuitEvent();
						executeGetEventList();
					}
				};

				new CloseAlertDialog(EventActivity.this, R.string.notice,
						R.string.rejoin, positive, negative).show();
				break;

			case ID_NOT_FOUND:
				executeGetEventList();
				break;

			default:
				unknownMessage(message);
				break;
			}

		}

		// ////////////////////////////////////////////////////////////////////
		// 이벤트 업데이트 시
		// ////////////////////////////////////////////////////////////////////
		private void receiveEventList() {

			switch (resultState) {
			case SOCKET_SUCCESS:
				updateEventApater((IdentityList) resultValue);
				break;

			case SOCKET_FAIL:
				uponFail();
				break;

			case SOCKET_EXCEPTION:
				executeGetEventList();
				break;

			default:
				unknownMessage(resultState);
				break;
			}
		}

		// ////////////////////////////////////////////////////////////////////
		// 공용 메소드
		// ////////////////////////////////////////////////////////////////////
		private void uponFail() {
			OnClickListener listener = new OnClickListener() {

				public void onClick(DialogInterface dialog, int which) {
					finish();
				}
			};

			new CloseAlertDialog(EventActivity.this, R.string.notice,
					R.string.disconnect_server, listener).show();
		}

		private void UponException(OnClickListener pListener,
				OnClickListener nListener) {
			new CloseAlertDialog(EventActivity.this, R.string.notice,
					R.string.fail_connect_server + R.string.reconnect,
					pListener, nListener).show();
		}

		private void startEventMap(Event event) {
			Intent intent = new Intent(EventActivity.this,
					EventMapActivity.class);
			intent.putExtra(TYPE.EVENT, event);
			startActivity(intent);
		}

		private void unknownMessage(STATE state) {
			new CloseAlertDialog(EventActivity.this, R.string.notice,
					"알 수 없는 STATE (R.string) - " + state.name(), null).show();

		}

		private void unknownMessage(SocketMessage message) {
			new CloseAlertDialog(EventActivity.this, R.string.notice,
					"알 수 없는 MESSAGE (R.string) - " + message.name(), null)
					.show();
		}

	};

	private void updateEventApater(IdentityList eventList) {
		this.events.clear();

		Iterator<Identity> iterator = eventList.iterator();
		while (iterator.hasNext()) {
			Identity identity = (Identity) iterator.next();
			this.events.add(identity);
		}

		adapter.notifyDataSetChanged();
	}

	private void executeGetEventList() {
		if (ThreadManager.isInThread(requestEventList) == false) {
			progressShow();
			requestEventList = new CommunicationManager();
			ThreadManager
					.excute(requestEventList, mHandler, REQUEST_EVENT_LIST);
		}
	}

	private void executeCheckInEvent(String memberId) {
		if (ThreadManager.isInThread(requestCreateEvent) == false) {
			progressShow();
			requestCheckInEvent = new CommunicationManager();
			ThreadManager.excute(requestCheckInEvent, mHandler, IS_IN_EVENT,
					memberId);
		}
	}

	private void executeCreateEvent(Event event) {
		if (ThreadManager.isInThread(requestCreateEvent) == false) {
			progressShow();
			requestCreateEvent = new CommunicationManager();
			ThreadManager.excute(requestCreateEvent, mHandler, CREATE_EVENT,
					event);
		}
	}

	private void executeJoinEvent(Event event) {

		if (ThreadManager.isInThread(requestJoinEvent) == false) {
			progressShow();
			requestJoinEvent = new CommunicationManager();
			ThreadManager.excute(requestJoinEvent, mHandler, EVENT_JOIN,
					new EventData(event.getId(), mHelper.dbGetMyId()));
		}
	}

	private void executeGetEvent(EventData data) {
		if (ThreadManager.isInThread(requestEvent) == false) {
			progressShow();
			requestEvent = new CommunicationManager();
			ThreadManager.excute(requestEvent, mHandler, REQUEST_EVENT_INFO,
					data);
		}
	}

	private void executeQuitEvent() {

		if (ThreadManager.isInThread(requestQuitEvent) == false) {
			progressShow();
			requestQuitEvent = new CommunicationManager();
			ThreadManager.excute(requestQuitEvent, mHandler, EVENT_QUIT,
					new EventData(mHelper.dbGetEventID(), mHelper.dbGetMyId()));
			try {
				requestQuitEvent.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

	private synchronized void progressShow() {
		if (mProgress.isShowing() == false) {
			mProgress.show();
		}
	}
}
